﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
namespace YZH.Audio.Disting
{
    /// <summary>
    /// 录音并识别文字
    /// </summary>
    public class RecorderDisting:IDisposable
    {
        //private readonly Asr _asr;
        private VoiceDistingDriver _disDriver;
        private Audio.AudioRecorderDriver _recorder;
        
        private Queue<byte[]> _buffer=new Queue<byte[]>();
        private int _bufferCount = 0;

        private const int _sleepErrorCount = 5; //无数据计数 当10次以上认为录音机工作异常,约2s
        private const int _bufferOverErrorCount = 40; //缓冲溢出错误次数 
        private const int _nomanErrorTimeCount = 30;  //30秒无人说话发出 消息
        private const int _sayCompleteCount = 5;       //当已经说过话，后面5次没说话，认为一长句结束

        StringBuilder _strBuilder = new StringBuilder();

        private Thread _thread;
        bool _isService = false;

        int sessionCount = 3;

        private AutoResetEvent m_RecordEvent = new AutoResetEvent(false);
        
        public Audio.AudioRecorderDriver Recorder
        {
            get
            {
                return _recorder;
            }
        }

        public delegate void OnMessageHandler(object obj, string msg,bool isStop);
        public OnMessageHandler OnMessage;
        private void RaiseOnMessage(object obj, string msg, bool isStop)
        {
            if (_isService == false) return;
            var tmp = OnMessage;
            if (tmp != null)
                tmp(obj, msg,isStop);
        }
        public RecorderDisting()
        {
            //_asr = new Asr("fkL5RDVVoiNMjofSxgpGgyVi", "TPouqn4UlyHwQDbD7de0uxQGvMsK0iam");
            //_asr.DebugLog = true;
            AddMessage("初始化语音识别器...");
            _disDriver = new VoiceDistingDriver();
            
            _recorder = new AudioRecorderDriver(new WaveFormat(16000,16,1),-1,3,6400);
            _recorder.OnWaveDataArrive = new OnWaveDataArriveHandler((obj,data) =>
            {
                if (_isService == false) return true;
                lock (_buffer)
                {                    
                    _bufferCount++;
                    _buffer.Enqueue(data);
                }
                AddMessage(string.Format("收到录音设备数据,当前数据条数{0}", _bufferCount));
                return true;
            });
        }
        ~RecorderDisting()
        {
            Dispose();
        }
        bool isFirst = true;
        private void Working()
        {
            int nosayCount = 0;//没人说话计数

            int sleepCount = 0;
            isFirst = true;

            lock (_buffer)
            {
                _bufferCount = 0;
                _buffer.Clear();
            }
            DateTime? startTime = null;

            while (_isService)
            {
                try
                {
                    byte[] data = null;
                    int rcount = _bufferCount;

                    if (rcount <= 0)  //无数据
                    {
                        sleepCount++;
                        AddMessage(string.Format("缓冲数据为0，当前次数{0}", sleepCount));
                        if (sleepCount >= _sleepErrorCount)
                        {
                            AddMessage(string.Format("-------------------------------------------------------------录音器错误"));
                            sleepCount = 0;
                            RaiseOnMessage(this, "err.recorder", true);
                            AutoStop();
                            return;
                        }
                        Thread.Sleep(400);
                        continue;
                    }
                    else if (rcount > _bufferOverErrorCount)
                    {
                        //累积太长的句子
                        sleepCount = 0;
                        AddMessage(string.Format("-------------------------------------------------------------数据缓冲溢出"));
                        RaiseOnMessage(this, "err.bufover", true);
                        AutoStop();
                        return;
                    }
                    sleepCount = 0;

                    if (_isService == false) break;
                    lock (_buffer)
                    {
                        data = _buffer.Dequeue();
                        _bufferCount--;
                    }
                    //识别数据
                    //Newtonsoft.Json.Linq.JObject result=null;
                    //try
                    //{
                    //    result = _asr.Recognize(data, "pcm", 8000);
                    //}
                    //catch
                    //{
                    //    continue;
                    //}
                    string tmpStr = "";
                    //if (result != null && result["result"] != null)
                    //{
                    //    var lst = Newtonsoft.Json.JsonConvert.DeserializeObject<List<string>>(result["result"].ToString());
                    //    foreach (var itm in lst)
                    //        tmpStr += itm;
                    //}
                    if (_isService == false) break;
                    AddMessage(string.Format("开始执行数据解析"));

                    //Random rnd = new Random();
                    //int rndData=rnd.Next(100);
                    //if(rndData<10)
                    //{
                    //    Thread.Sleep(300);
                    //}
                    //else if(rndData>98)
                    //{
                    //    tmpStr = "你好";
                    //}

                    tmpStr = _disDriver.GetMessage(data);

                    AddMessage(string.Format("完成执行数据解析"));
                    if (_isService == false) break;
                    if (string.IsNullOrEmpty(tmpStr))// 没识别出来文字
                    {
                        if (isFirst)
                        {
                            if (startTime == null)
                                startTime = DateTime.Now;
                            else
                            {
                                DateTime nowTime = DateTime.Now;
                                if ((nowTime - startTime.Value).TotalSeconds > _nomanErrorTimeCount)
                                {
                                    AddMessage(string.Format("-------------------------------------------------------------长时间无人说话"));
                                    //很长无人说话
                                    startTime = null;
                                    RaiseOnMessage(this, "err.nomen", true);
                                    AutoStop();
                                    return;
                                }
                            }
                            continue;
                        }
                        else//识别出过文字，但后续一段时间没说话
                        {
                            nosayCount++;
                            if (nosayCount > _sayCompleteCount) //长句结束
                            {
                                AddMessage(string.Format("-------------------------------------------------------------说话结束"));
                                RaiseOnMessage(this, "done", true);
                                AutoStop();
                                return;
                            }
                        }
                    }
                    else//识别文字
                    {
                        nosayCount = 0;
                        if (isFirst)
                        {
                            isFirst = false;
                        }
                        AddMessage(string.Format("-------------------------------------------------------------说话：{0}", tmpStr));
                        RaiseOnMessage(this, tmpStr, false);
                        continue;
                    }
                }
                catch (Exception e3)
                {
                    if (e3.Message.StartsWith("err."))
                    {
                        RaiseOnMessage(this, e3.Message, true);
                        AutoStop();
                        return;
                    }
                }
            }//end while
        }
        public void Start()
        {
            lock (_lockObj)
            {
                _isService = true;
                AddMessage(string.Format("准备启动语音识别器...", _bufferCount));
                _thread = new Thread(new ThreadStart(Working));
                _thread.Start();
                _recorder.Start();
            }
        }

        private void AutoStop()
        {
            if (_isService == false) return;
            ThreadPool.QueueUserWorkItem(new WaitCallback((obj) => {
                if (_isService == false) return ;
                Stop();
            }));
        }
        private object _lockObj = new object();
        public void Stop()
        {
            lock (_lockObj)
            {
                _isService = false;
                _recorder.Stop();
                try
                {
                    if (_thread != null&&_thread.ThreadState==System.Threading.ThreadState.Running)
                    {
                        //_thread.Abort();
                        _thread.Join();
                    }
                }
                catch { }
                finally { _thread = null; }                
            }
        }
        [Conditional("TEST")]
        internal void AddMessage(string msg)
        {
            lock (_strBuilder)
            {
                _strBuilder.AppendFormat(string.Format("{0}---{1}\r\n", DateTime.Now, msg));
            }
        }
        public string GetMsg()
        {
            lock (_strBuilder)
            {
                string str = _strBuilder.ToString();
                _strBuilder.Clear();
                return str;
            }
        }

        public void Dispose()
        {
            Stop();
            _recorder.Dispose();
            _disDriver.Dispose();
            GC.SuppressFinalize(this);
        }
    }
}
